package sessions.requestFriendshipSession;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;

import javax.ejb.Stateless;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import sessions.friendshipSession.FriendshipSessionRemote;
import entities.Friendship;
import entities.FriendshipRequest;
import entities.Utente;

@Stateless
public class FriendshipRequestSession implements
		FriendshipRequestSessionRemote, FriendshipRequestSessionLocal {
	@PersistenceContext(unitName = "MPHProject")
	private EntityManager manager;

	/**
	 * inserisce una richiesta di amicizia nel database
	 * 
	 * @param idSender
	 *            : utente che invia la richiesta
	 * @param idReceiver
	 *            : utente che riceve la richiesta
	 * @param direct
	 *            : se e' true la richiesta e' diretta
	 * @param date
	 *            : data odierna
	 * @return l'id della richiesta
	 */
	public int insertFriendshipRequest(int idSender, int idReceiver, Date date,
			boolean direct, boolean autoSent) {
		try {
			//cancella eventuali richieste di amicizia indiretta tra i due
			eraseFrendshipRequest(idSender, idReceiver);
			Query q;
			FriendshipRequest request = new FriendshipRequest();
			q = manager.createQuery("FROM Utente WHERE id=:ID");
			q.setParameter("ID", idSender);
			request.setSender((Utente) q.getSingleResult());
			Query p = manager.createQuery("FROM Utente WHERE id=:ID");
			p.setParameter("ID", idReceiver);
			request.setReceiver((Utente) p.getSingleResult());
			request.setDate(date);
			request.setDiretta(direct);
			request.setAutoSent(autoSent);
			manager.persist(request);
			return request.getId();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return 0;
	}

	private void eraseFrendshipRequest(int idUser1, int idUser2) {
		FriendshipRequest friendshipRequest;
		try {
			Query q = manager.createNativeQuery(
					"SELECT * FROM RichiestaAmicizia WHERE (idu1=:idUser1 AND idu2=:idUser2) OR"
							+ "(idu2=:idUser1 AND idu1=:idUser2)",
					FriendshipRequest.class);
			q.setParameter("idUser1", idUser1);
			q.setParameter("idUser2", idUser2);
			friendshipRequest=(FriendshipRequest) q.getSingleResult();
			if(friendshipRequest!=null){
				rejectRequest(friendshipRequest.getId());
			}
		} catch (Exception exc) {
			// se c'e' un eccezzione vuol dire che non e' stata trovata alcuna
			// tupla
		}
	}

	/**
	 * restituisce la richiesta cercata
	 * 
	 * @param ID
	 *            : id della richiesta
	 * 
	 * @return
	 */
	public FriendshipRequest getFriendshipRequest(int ID) {
		try {
			Query q = manager
					.createQuery("FROM FriendshipRequest ra WHERE ra.id=:ID");
			q.setParameter("ID", ID);
			return (FriendshipRequest) q.getSingleResult();
		} catch (Exception exc) {
		}
		return null;
	}

	/**
	 * restituisce tutte le richieste di amicizia inviate da un utente
	 * 
	 * @param idUser
	 *            : l'utente che ha inviato le richieste
	 * @param direct
	 *            : amicizia inviata da utente se vero, se falso amicizia
	 *            suggerita
	 * @param autoSent
	 *            : richietsa inviata da sistema se vero
	 * @return
	 */
	public ArrayList<FriendshipRequest> SentRequests(int idUser,
			boolean direct, boolean autoSent) {
		try {
			Query q = manager
					.createNativeQuery(
							"SELECT * FROM RichiestaAmicizia WHERE IDU1=:ID AND diretta=:direct AND autoSent=:autoSent",
							FriendshipRequest.class);
			q.setParameter("ID", idUser);
			q.setParameter("direct", direct);
			q.setParameter("autoSent", autoSent);
			return (ArrayList<FriendshipRequest>) q.getResultList();
		} catch (Exception exc) {
		}
		return null;

	}

	/**
	 * restituisce tutte le richieste di amicizia ricevute da un utente
	 * 
	 * @param idUser
	 *            : l'utente che ha ricevuto le richieste
	 * @param direct
	 *            : amicizia inviata da utente se vero, se falso amicizia
	 *            suggerita
	 * @param autoSent
	 *            : richietsa inviata da sistema se vero
	 * @return
	 */
	public ArrayList<FriendshipRequest> ReceveidRequests(int idUser,
			boolean direct, boolean autoSent) {

		try {
			Query q = manager
					.createNativeQuery(
							"SELECT * FROM RichiestaAmicizia WHERE IDU2=:ID AND diretta=:direct AND autoSent=:autoSent",
							FriendshipRequest.class);
			q.setParameter("ID", idUser);
			q.setParameter("direct", direct);
			q.setParameter("autoSent", autoSent);
			return (ArrayList<FriendshipRequest>) q.getResultList();
		} catch (Exception exc) {
			exc.printStackTrace();
		}
		return null;

	}

	/**
	 * controlla se un utente ha gia' effettuato una richiesta di amicizia verso
	 * un altro utente
	 * 
	 * @param idUser1
	 *            : id del primo utente
	 * @param idUser2
	 *            : id del secondo utente
	 * @return
	 */
	public boolean checkRequestFriendships(int idUser1, int idUser2) {
		try {
			Query q = manager.createNativeQuery(
					"SELECT * FROM RichiestaAmicizia WHERE (idu1=:idUser1 AND idu2=:idUser2) OR"
							+ "(idu2=:idUser1 AND idu1=:idUser2)",
					FriendshipRequest.class);
			q.setParameter("idUser1", idUser1);
			q.setParameter("idUser2", idUser2);
			q.getSingleResult();
		} catch (Exception exc) {
			// se c'e' un eccezzione vuol dire che non e' stata trovata alcuna
			// tupla
			return false;
		}
		return true;
	}

	/**
	 * accetta una richiesta di amicizia
	 * 
	 * @param idRequest
	 *            l'id della richiesta da accettare
	 */
	public int acceptRequest(int idRequest) {
		Friendship friendship = new Friendship();
		FriendshipRequest friendshipRequest = getFriendshipRequest(idRequest);
		friendship.setUser1(friendshipRequest.getSender());
		friendship.setUser2(friendshipRequest.getReceiver());
		if (friendshipRequest.isDiretta()) {
			// invio eventuali richieste di amicizia indirette
			suggestIndirectFriends(friendshipRequest.getSender().getId(),
					friendshipRequest.getReceiver().getId());
			suggestIndirectFriends(friendshipRequest.getReceiver().getId(),
					friendshipRequest.getSender().getId());
		}
		manager.persist(friendship);
		rejectRequest(idRequest);
		return friendship.getId();
	}

	/**
	 * rifiuta una richiesta di amicizia
	 * 
	 * @param idRequest
	 *            l'id della richiesta da rifiutare
	 */
	public boolean rejectRequest(int idRequest) {
		try {
			manager.remove(getFriendshipRequest(idRequest));
			if (getFriendshipRequest(idRequest) == null)
				return true;
		} catch (Exception exc) {
		}
		return false;
	}

	/**
	 * restituisce tutti gli amici dell'utente che ha accettato la richiesta
	 * 
	 * @param idUser1
	 *            : utente che ha inviato la richiesta
	 * @param idUser2
	 *            : utente che ha ricevuto la richiesta
	 * @return
	 */
	public void suggestIndirectFriends(int idUser1, int idUser2) {
		ArrayList<Friendship> friendshipsUser1, friendshipsUser2;
		int idu1, idu2, idPossibleFriend, idFriendUser2;
		boolean friendAlreadyHad = false;
		Context jndiCtx;
		Calendar now = Calendar.getInstance();
		Date date = now.getTime();
		try {
			jndiCtx = new InitialContext();
			FriendshipSessionRemote friendSession = (FriendshipSessionRemote) jndiCtx
					.lookup("Progetto/FriendshipSession/remote");
			// prendo tutte le amicizie degli utenti
			friendshipsUser1 = friendSession.getUserFriendships(idUser1);
			friendshipsUser2 = friendSession.getUserFriendships(idUser2);
			if (friendshipsUser1 != null)
				for (Friendship possibleNewFriendship : friendshipsUser1) {
					friendAlreadyHad = false;
					idu1 = possibleNewFriendship.getUser1().getId();
					idu2 = possibleNewFriendship.getUser2().getId();
					// prendo il possibile amico indiretto
					if (idu1 == idUser1)
						idPossibleFriend = idu2;
					else
						idPossibleFriend = idu1;
					if (friendshipsUser2 != null)
						for (Friendship oldFriendshipUser2 : friendshipsUser2) {
							if (!friendAlreadyHad) {
								idu1 = oldFriendshipUser2.getUser1().getId();
								idu2 = oldFriendshipUser2.getUser2().getId();
								// prendo il possibile amico indiretto
								if (idu1 == idUser2)
									idFriendUser2 = idu2;
								else
									idFriendUser2 = idu1;
								if (idFriendUser2 == idPossibleFriend) {
									friendAlreadyHad = true;
								}
							}
						}
					if (!friendAlreadyHad) {
						if (!this.checkRequestFriendships(idPossibleFriend,
								idUser2)) {
							// se non c'e' gia' una richiesta di amicizia tra i due
							this.insertFriendshipRequest(idPossibleFriend,
									idUser2, date, false, true);
						}
					}
				}
		} catch (Exception exc) {
			exc.printStackTrace();
		}
	}

	/**
	 * controlla se c'e' un suggerimento di amicizia verso un altro utente
	 * 
	 * @param idUser1
	 *            : id del primo utente
	 * @param idUser2
	 *            : id del secondo utente
	 * @return
	 */
	public boolean checkIndirectRequestFriendships(int idUser1, int idUser2) {
		try {
			Query q = manager
					.createNativeQuery(
							"SELECT * FROM RichiestaAmicizia WHERE ((idu1=:idUser1 AND idu2=:idUser2) OR"
									+ "(idu2=:idUser1 AND idu1=:idUser2)) AND diretta=0",
							FriendshipRequest.class);
			q.setParameter("idUser1", idUser1);
			q.setParameter("idUser2", idUser2);
			q.getSingleResult();
		} catch (Exception exc) {
			// se c'e' un eccezzione vuol dire che non e' stata trovata alcuna
			// tupla
			return false;
		}
		return true;
	}

	// elimina tutte le richieste di amicizia di un utente
	public boolean eraseUserRequest(int userId) {
		ArrayList<FriendshipRequest> requests;
		;
		try {
			Query q = manager
					.createNativeQuery(
							"SELECT * FROM RichiestaAmicizia WHERE IDU1=:ID OR IDU2=:ID",
							FriendshipRequest.class);
			q.setParameter("ID", userId);
			requests = (ArrayList<FriendshipRequest>) q.getResultList();
			if (requests != null && requests.size() > 0)
				for (FriendshipRequest request : requests)
					rejectRequest(request.getId());
		} catch (Exception exc) {
			exc.printStackTrace();
			return false;
		}
		return true;
	}
}
